package com.fjzx.androidframe.network;

import android.arch.lifecycle.LiveData;


import com.fjzx.androidframe.global.entity.Resource;
import com.fjzx.androidframe.network.entity.BaseResponse;
import com.fjzx.androidframe.xlogger.XLogger;

import java.util.concurrent.Callable;

import bolts.Task;

/**
 * 本地数据库和带网络请求的数据获取器
 *
 * @param <ResultType>
 * @author xiongyongcong
 */
public abstract class NetworkAndDatabaseFetcher<ResultType> {
    private BaseLiveData<ResultType> result;

    public NetworkAndDatabaseFetcher(String action) {
        result = new BaseLiveData<>(new Resource<>(action));
        reload();
    }

    public void reload() {
        // 设置状态为加载中
        result.loading();
        // 从数据库中获取数据
        LiveData<ResultType> dbSource = loadFromDb();
        result.addSource(dbSource, data -> {
            // 判断是否需要从网络获取数据
            result.removeSource(dbSource);
            if (data == null || shouldFetch(data)) {
                // 从网络获取数据
                fetchFromNetwork(dbSource, data);
            } else {
                result.addSource(dbSource, newData -> {
//                    result.removeSource(dbSource);
                    result.success(newData);
                });
            }
        });
    }

    /**
     * 从网络获取数据
     * @param dbSource
     * @param data
     */
    private void fetchFromNetwork(LiveData<ResultType> dbSource, ResultType data) {
        // 创建网络请求
        LiveData<BaseResponse<ResultType>> apiResponse = loadFromNetwork();
        result.addSource(apiResponse, response -> {
            // 停止监听
            result.removeSource(apiResponse);
            if (response.isSuccessful() && response.getData() != null) {
                // 若网络请求成功
                saveResultAndReLoad(response, data);
            } else {
                XLogger.e("fetchFromNetwork error " + response.getMessage());
                // 网络请求错误
                onFetchFailed();
                result.addSource(dbSource, newData -> {
//                    result.removeSource(dbSource);
                    result.success(newData);
                });
            }
        });
    }

    /**
     * 保存数据到数据库并重新加载
     *
     * @param response
     * @param data
     */
    private void saveResultAndReLoad(BaseResponse<ResultType> response, ResultType data) {
        Task.callInBackground((Callable<Void>) () -> {
            // 保存结果到数据库
            saveCallResult(data, response.getData());
            LiveData<ResultType> dbSource = loadFromDb();
            result.addSource(dbSource, dbData -> {
                result.success(dbData);
            });
            return null;
        });
    }

    /**
     * 以LiveData返回
     *
     * @return
     */
    public final BaseLiveData<ResultType> getAsLiveData() {
        return result;
    }

    /**
     * 网络请求错误
     */
    protected void onFetchFailed() {
    }

    /**
     * 是否需要从网络获取
     *
     * @param data
     * @return
     */
    protected boolean shouldFetch(ResultType data) {
        return true;
    }

    /**
     * 从数据库加载
     *
     * @return
     */
    protected abstract LiveData<ResultType> loadFromDb();

    /**
     * 创建网络请求
     *
     * @return
     */
    protected abstract LiveData<BaseResponse<ResultType>> loadFromNetwork();

    /**
     * 保存网络请求数据到数据库
     *
     * @param oldData
     * @param newData
     */
    protected abstract void saveCallResult(ResultType oldData,  ResultType newData);
}
